#ifndef GridView_First
#define GridView_First
#ifdef __GNUG__
#pragma interface
#endif

#include "View.h"
#include "Region.h"

class Clipper;

struct gridinfo {
	int x, y, bs;
};

enum GridSelectionOptions {
	eSelRange         = BIT(0),
	eSelStuckToBorder = BIT(1),
	eSelExtend        = BIT(2)
};

//---- CellAttribute -----------------------------------------------------------

struct CellAttributes {
	Ink *ink;
	Font *font;
	VObjAlign align;

	CellAttributes();
	CellAttributes(Ink*, Font*, VObjAlign);
	CellAttributes(const CellAttributes *ca);
};

//---- GridView ----------------------------------------------------------------

class GridView: public View {
public:
	MetaDef(GridView);

	GridView(EvtHandler *eh, bool cache= TRUE);
	~GridView();

	//---- cache
	void SetModified();
				
	//---- querying layout
	int GetRows();
	int GetCols();
	Point GetGap(const Point &cell);
	int ColWidth(int col);
	int RowHeight(int row);
	int RowBase(int row);
	int ColOrigin(int col);
	int RowOrigin(int row);
	int GetRowGap(int);
	int GetColGap(int);

	//---- coordinates to cells
	virtual bool PosToCell(const Point &pos, Point *cell);
		// returns cell containing point
	bool RectToCell(const Rectangle &rect, Rectangle *cells);
		// returns cell containing point

	//---- cells to coordinates
	Rectangle GetCellRect(const Point &cell);
	Rectangle GetCellRect(const Rectangle &cells);
	Rectangle GetGapCellRect(const Point &cell);
	Rectangle GetGapCellRect(const Rectangle &cells);
	Point GetCellOrigin(const Point &cell);
	Point GetCellExtent(const Point &cell);

	//---- selection
	virtual void DoSelect(int clicks);
	virtual void SetSelection(const Region &newsel);
	void SetSelection(const Rectangle &newsel);
	void SetSelection(const Point &cell);
	void ClearSelection(bool redraw= TRUE);
	Region GetSelection()
		{ return selection; }

	//---- attributes
	virtual CellAttributes *GetCellAttributes(const Point &cell);

protected:
	//---- cache
	virtual bool CheckCache();

	//---- drawing output operations
	void Draw(Rectangle);
	virtual void DrawCell(const Point &cell, const Rectangle&, const Rectangle&, bool);
	virtual void DrawGridRect(Direction dir, int x, const Rectangle &r);

	//---- events
	Command *DoLeftButtonDownCommand(Point lp, Token t, int clicks);
	void ConstrainScroll(Point *p);

	//---- override these to implement layout
	virtual Point GetColsRows();
	virtual int GetGap(Direction dir, int colrow);
	virtual int GetColWidth(int col);
	virtual int GetRowHeight(int row);
	virtual int GetRowBase(int row);
	virtual int GetColOrigin(int col);
	virtual int GetRowOrigin(int row);
	virtual Metric CellSize(const Point &cell);
	Metric GetMinSize();

protected:
	Point border;
	Region selection;
	bool cache, modified;
	gridinfo *grid;
};

//---- GridSelector ------------------------------------------------------------

class GridSelector: public Command {
public:
	GridSelector(GridView *gv, bool r, int c, int cl);
	void TrackFeedback(Point, Point, bool);
	Command *TrackMouse(TrackPhase, Point, Point, Point);
protected:
	GridView *gridview;
	bool range;
	Point anchor;
	int code, clicks;
	Region sel;
};

//---- inlines -----------------------------------------------------------------

inline void GridView::SetModified()
	{ modified= TRUE; }
inline int GridView::GetRowGap(int row)
	{ return GetGap(eHor, row); }              
inline int GridView::GetColGap(int col)
	{ return GetGap(eVert, col); }
inline int GridView::ColWidth(int col)
	{ return CheckCache() ? grid[col+1].x-grid[col].x-GetColGap(col)
						: GetColWidth(col); }
inline int GridView::RowHeight(int row)
	{ return CheckCache() ? grid[row+1].y-grid[row].y-GetRowGap(row)
						: GetRowHeight(row); }
inline int GridView::RowBase(int row)
	{ return CheckCache() ? grid[row].bs : GetRowBase(row); }
inline int GridView::ColOrigin(int col)
	{ return CheckCache() ? grid[col].x : GetColOrigin(col); }
inline int GridView::RowOrigin(int row)
	{ return CheckCache() ? grid[row].y : GetRowOrigin(row); }
inline void GridView::ClearSelection(bool)
	{ SetSelection(gRect0); }
inline void GridView::SetSelection(const Point &cell)
	{ SetSelection(Rectangle(cell, gPoint1)); }
inline Point GridView::GetCellOrigin(const Point &cell)
	{ return Point(ColOrigin(cell.x), RowOrigin(cell.y)); }
inline Point GridView::GetCellExtent(const Point &cell)
	{ return Point(ColWidth(cell.x), RowHeight(cell.y)); }
inline Point GridView::GetGap(const Point &cell)
	{ return Point(GetColGap(cell.x), GetRowGap(cell.y)); }
inline int GridView::GetRows()
	{ return GetColsRows().y; }
inline int GridView::GetCols()
	{ return GetColsRows().x; }

#endif

